package com.neuedu.weishi.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neuedu.weishi.entity.Member;
import com.neuedu.weishi.mapper.MemberMapper;
import com.neuedu.weishi.service.IMemberService;
import com.neuedu.weishi.util.*;
import com.neuedu.weishi.util.mail.EmailService;
import com.neuedu.weishi.vo.ResponseData;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private HttpServletRequest request;

    @Override
    public ResponseData register(String email, String password, String code) {
        if (StrUtil.isEmpty(email)) {
            return ResponseData.createFail("邮箱不能为空");
        }
        if (StrUtil.isEmpty(password)) {
            return ResponseData.createFail("密码不能为空");
        }
        if (StrUtil.isEmpty(code)) {
            return ResponseData.createFail("验证码不能为空");
        }
        //检验验证码 key:register:email:code:+当前邮箱地址
        String codeKey = "register:email:code:" + email.toUpperCase();
        String redisCode = (String) redisUtils.get(codeKey);
        if (StrUtil.isEmpty(redisCode)) {
            return ResponseData.createFail("验证码已过期");
        }
        //检验验证码是否正确,不区分大小写
        if (!redisCode.equalsIgnoreCase(code)) {
            return ResponseData.createFail("验证码错误");
        }
        //删除验证码
        redisUtils.del(codeKey);
        if (!validateEmail(email)) {
            return ResponseData.createFail("邮箱格式错误");
        }
        // 校验邮箱是否已注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (count > 0) {
            return ResponseData.createFail("邮箱【" + email + "】已注册");
        }
        //验证密码格式
        if (!validatePassword(password)) {
            return ResponseData.createFail("密码格式错误");
        }
        //注册
        Member member = new Member();
        member.setEmail(email);
        //密码加密
        password = encryptPassword(password);
        member.setPassword(password);
        member.setRegisterTime(new Date());//注册时间默认为java后台服务器时间
        member.setMemberStatus(1);//设置会员用户状态. 1:正常
        int rows = getBaseMapper().insert(member);
        return ResponseData.success(rows);
    }

    /**
     * 密码加密
     *
     * @param password
     * @return
     */
    private static String encryptPassword(String password) {
        String url = "https://www.weishi.com/?i=";
        for (int i = 1; i <= 15; i++) {
            password = SHAEncryptUtils.getSHA512(url + password);
        }
        for (int i = 1; i <= 15; i++) {
            password = MD5.getMD5(password + url);
        }
        return password;
    }

    /**
     * 使用正则表达式验证密码，密码由大小写字母、数字、标点符号组成，长度范围为 8 - 20，
     * 必须包含数字、大写字母、小写字母、标点符号其中三种，不能含有空白字符和转义字符
     *
     * @param password 待验证的密码
     * @return 若密码符合规则返回 true，否则返回 false
     */
    public static boolean validatePassword(String password) {
        if (password == null || password.length() < 8 || password.length() > 20) {
            return false;
        }

        // 检查是否包含空白字符或转义字符
        if (password.matches(".*[\\s\\\\].*")) {
            return false;
        }

        // 定义不同字符类型的正则表达式
        int criteriaMet = 0;
        if (password.matches(".*[0-9].*")) { // 数字
            criteriaMet++;
        }
        if (password.matches(".*[A-Z].*")) { // 大写字母
            criteriaMet++;
        }
        if (password.matches(".*[a-z].*")) { // 小写字母
            criteriaMet++;
        }
        if (password.matches(".*[^a-zA-Z0-9\\s].*")) { // 标点符号
            criteriaMet++;
        }

        // 必须满足至少三种条件
        return criteriaMet >= 3;
    }

    /**
     * 验证电子邮箱格式是否合法
     *
     * @param email 待验证的邮箱地址
     * @return true-格式合法，false-格式不合法
     */
    private boolean validateEmail(String email) {
        if (StrUtil.isEmpty(email)) {
            return false;
        }
        // 邮箱格式正则表达式（保持原校验规则不变）
        String emailRegex = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$";
        return email.matches(emailRegex);
    }

    @Override
    public ResponseData sendRegisterCode(String email) {
        if (StrUtil.isEmpty(email)) {
            return ResponseData.createFail("邮箱不能为空");
        }
        //校验邮箱格式
        if (!validateEmail(email)) {
            return ResponseData.createFail("邮箱格式错误");
        }
        //校验邮箱是否已注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (count > 0) {
            return ResponseData.createFail("邮箱【" + email + "】已注册");
        }

        //判断当前邮箱是否重复发送邮件验证码
        String codeKey = "register:email:code:" + email.toUpperCase();
        if (redisUtils.hasKey(codeKey)) {
            return ResponseData.createFail("请不要重复发送邮箱验证码");
        }
        String code = RandomCodeUtils.getCheckCode();
        //设置验证码过期时间为180秒
        redisUtils.set(codeKey, code, 180);
        //发送邮件
        try {
            EmailService.sentMailHtml("会员注册", "欢饮注册xx视频网会员,您的验证码为:<span style='color:blue;font-size:24px'>" + code + "</span>.有效期为180秒", email);
        } catch (Exception e) {
            redisUtils.del(codeKey);
            e.printStackTrace();
            return ResponseData.createFail("发送邮件失败");
        }
        return ResponseData.success("发送成功");
    }

    @Override
    public ResponseData login(String email, String password) {
        if (StrUtil.isEmpty(email)) {
            return ResponseData.createFail("邮箱不能为空");
        }
        if (StrUtil.isEmpty(password)) {
            return ResponseData.createFail("密码不能为空");
        }
        if (!validateEmail(email)) {
            return ResponseData.createFail("邮箱格式错误");
        }
        //判断是否重复登录
        String loginKey = "login:email:" + email.toUpperCase();
        if (redisUtils.hasKey(loginKey)) {
            return ResponseData.createFail("您已在其他设备登录,如非本人操作,请及时修改密码");
        }
        //密码密码 如果MD5(x)==MD5(y)为true 则x=y
        password = encryptPassword(password);
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        queryWrapper.eq("password", password);
        Member member = getBaseMapper().selectOne(queryWrapper);
        if (member == null) {
            return ResponseData.createFail("邮箱或密码错误");
        }
        int status = member.getMemberStatus();
        if (2 == status) {
            return ResponseData.createFail("您的账号已被禁封");
        }
        if (3 == status) {
            return ResponseData.createFail("您的账号已注销");
        }
        if (1 != status) {
            return ResponseData.createFail("您的账号状态异常,请联系管理员");
        }
        //登录成功,在redis中保存邮箱,作用:用于判断该邮箱是否已登录,即避免重复登录
        redisUtils.set(loginKey, email, 60 * 60 * 24 * 15);
        //签名
        String memberId = member.getMemberId().toString();
        String token = SignUtils.getToken(true,memberId, request);
        //将签名保存到redis中
        redisUtils.set("login:token:" + token, memberId, 60 * 60 * 24 * 15);
        return ResponseData.success(token);
    }

    @Override
    public ResponseData sendFindPwdCode(String email) {
        if (StrUtil.isEmpty(email)) {
            return ResponseData.createFail("邮箱不能为空");
        }
        //校验邮箱格式
        if (!validateEmail(email)) {
            return ResponseData.createFail("邮箱格式错误");
        }
        //校验邮箱是否已注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (0 == count) {
            return ResponseData.createFail("邮箱【" + email + "】未注册");
        }
        //判断当前邮箱是否重复发送找回邮件验证码
        String codeKey = "find:pwd:email:code:" + email.toUpperCase();
        if (redisUtils.hasKey(codeKey)) {
            return ResponseData.createFail("请不要重复发送找回密码邮箱验证码");
        }
        String code = RandomCodeUtils.getCheckCode();
        //设置验证码过期时间为180秒
        redisUtils.set(codeKey, code, 180);
        //发送邮件
        try {
            EmailService.sentMailHtml("找回密码", "您正在找回xx视频网会员密码,您的验证码为:<span style='color:blue;font-size:24px'>" + code + "</span>.有效期为180秒", email);
        } catch (Exception e) {
            redisUtils.del(codeKey);
            e.printStackTrace();
            return ResponseData.createFail("发送邮件失败");
        }
        return ResponseData.success("发送成功");
    }

    @Override
    public ResponseData resetPassword(String email, String code, String newPWD) {
        if (StrUtil.isEmpty(email)) {
            return ResponseData.createFail("邮箱不能为空");
        }
        if (StrUtil.isEmpty(code)) {
            return ResponseData.createFail("验证码不能为空");
        }
        if (StrUtil.isEmpty(newPWD)) {
            return ResponseData.createFail("新密码不能为空");
        }
        String codeKey = "find:pwd:email:code:" + email.toUpperCase();
        //校验验证码
        if (!redisUtils.hasKey(codeKey)) {
            return ResponseData.createFail("验证码已过期");
        }
        String redisCode = redisUtils.get(codeKey).toString();
        if (!redisCode.equals(code)) {
            return ResponseData.createFail("验证码错误");
        }
        redisUtils.del(codeKey);
        if (!validatePassword(newPWD)) {
            return ResponseData.createFail("密码格式错误");
        }
        String password = encryptPassword(newPWD);
        //更新密码
        UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("LOWER(email)", email.toLowerCase());
        updateWrapper.set("password", password);
        int rows = getBaseMapper().update(updateWrapper);
        return ResponseData.success(rows);
    }

    @Override
    public boolean checkToken(String token) {
        String tokenKey = "login:token:" + token;
        String memberId = (String) redisUtils.get(tokenKey);
        //验证token是否合法
        String currentToken = SignUtils.getToken(false,memberId, request);
        token=SignUtils.removeRandomStr(token);
        return currentToken.equals(token);
    }
    @Override
    public ResponseData updatePassword(String token, String oldPwd, String newPwd, String newConfirmPwd) {
        if(StrUtil.isEmpty(oldPwd)){
            return ResponseData.missParam("旧密码");
        }
        if(StrUtil.isEmpty(newPwd)){
            return ResponseData.missParam("新密码");
        }
        if(StrUtil.isEmpty(newConfirmPwd)){
            return ResponseData.missParam("新密码确认");
        }
        if(!newPwd.equals(newConfirmPwd)){
            return ResponseData.missParam("新密码和新密码确认不一致");
        }
        if(!validatePassword(oldPwd)){
            return ResponseData.missParam("旧密码格式错误");
        }
        if(!validatePassword(newPwd)){
            return ResponseData.missParam("新密码格式错误");
        }
        //1.检查会员用户是否存在
        int memberId=getMemberId(token);
        Member member=getById(memberId);
        if(member==null){
            return ResponseData.modifyFail("会员用户不存在");
        }
        //2.检查旧密码是否正确
        String password=member.getPassword();//数据库表中的旧密码
        oldPwd=encryptPassword(oldPwd);
        if(!password.equals(oldPwd)){
            return ResponseData.createFail("旧密码错误");
        }
        //3.检查旧密码与新密码是否相同
        newPwd=encryptPassword(newPwd);
        if(oldPwd.equals(newPwd)){
            return ResponseData.missParam("新密码不能与旧密码相同");
        }
        Member entity=new Member();
        entity.setMemberId(memberId);
        entity.setPassword(newPwd);
        int rows=getBaseMapper().updateById(entity);
        if(1==rows){
            //退出系统,删除令牌及登录邮箱
            String tokenKey="login:token:"+token;
            redisUtils.del(tokenKey);
            String loginKey = "login:email:" + member.getEmail().toUpperCase();
            redisUtils.del(loginKey);
        }
        return ResponseData.success(rows);
    }
    /**
     * 获取会员ID
     * @param token
     * @return
     */
    private  int getMemberId(String token){
        String tokenKey="login:token:"+token;
        String memberId=(String)redisUtils.get(tokenKey);
        if(memberId==null){
            throw  new IllegalArgumentException("无效的令牌");
        }
        return Integer.parseInt(memberId);
    }
}